package redis

import (
	"context"
	"gitee.com/xlizy/common-go/utils/zlog"
	"github.com/go-redis/redis/v8"
	"strconv"
	"time"
)

type RootConfig struct {
	Config redisConfig             `yaml:"redis"`
	Multi  map[string]*redisConfig `yaml:"redis-multi"`
}

type redisConfig struct {
	Addr     string `yaml:"addr"`
	Password string `yaml:"password"`
	DB       int    `yaml:"db"`
}

var _client *redis.Client
var _multiClient = make(map[string]*redis.Client)

func NewConfig() *RootConfig {
	return &RootConfig{}
}

func InitRedis(rc *RootConfig) {
	if rc.Multi != nil && len(rc.Multi) > 0 {
		for key, _config := range rc.Multi {
			cli := redis.NewClient(&redis.Options{
				Addr:     _config.Addr,     // redis地址
				Password: _config.Password, // redis没密码，没有设置，则留空
				DB:       _config.DB,       // 使用默认数据库
			})
			_multiClient[key] = cli
		}
	} else {
		// 初始化一个新的redis client
		_client = redis.NewClient(&redis.Options{
			Addr:     rc.Config.Addr,     // redis地址
			Password: rc.Config.Password, // redis没密码，没有设置，则留空
			DB:       rc.Config.DB,       // 使用默认数据库
		})
	}
}

func Cli() *redis.Client {
	return _client
}

func CliMulti(key string) *redis.Client {
	return _multiClient[key]
}

func RateLimit(ctx context.Context, cli *redis.Client, window, maxCnt int, key string) bool {
	isExits := cli.Exists(ctx, "EXISTS", key).Val()
	timeStamp := time.Now().Unix()
	if isExits == 0 {
		cli.LPush(ctx, key, timeStamp)
		cli.Expire(ctx, key, time.Duration(window)*time.Second)
		zlog.Info("限流结果:允许放行")
		return true
	}
	lens := cli.LLen(ctx, key).Val()
	end := 0
	list := cli.LRange(ctx, key, 0, lens).Val()
	for i := int(lens - 1); i >= 0; i-- {
		str := list[i]
		oldStamp, _ := strconv.ParseInt(str, 10, 64)
		if timeStamp-oldStamp < int64(window) {
			end = i
			break
		}
	}

	cli.LTrim(ctx, key, 0, int64(end))

	if end+1 < maxCnt {
		cli.LPush(ctx, key, timeStamp)
		cli.Expire(ctx, key, time.Duration(window)*time.Second)
		zlog.Info("限流结果:允许放行")
		return true
	}
	zlog.Info("限流结果:禁止操作")
	return false
}
